package cn.sc.summer.constant.util;

import lombok.Data;
import org.springframework.lang.NonNull;

import java.io.Serializable;
import java.util.function.*;

/**
 * 类名：便携的断言工具类，主要用作于消除if-else
 * T: 用于入参
 * P: 用于入参
 * U: 用于入参
 * R: 用于返回值
 *
 * @author a-xin
 * @date 2023/12/1 16:47
 */
public final class AssertUtil {

    /**
     * 根据条件执行function 有返回值
     *
     * @param param     断言参数信息
     * @param predicate 断言方法
     * @param function  具体执行方法
     * @param <R>       返回数据类型
     * @param <T>       断言参数类型
     * @return 执行方法后返回数据
     */
    public static <T, R> R functionIfPre(T param, @NonNull Predicate<T> predicate, @NonNull Supplier<R> function, R result) {
        if (predicate.test(param)) {
            return function.get();
        } else {
            return result;
        }
    }

    /**
     * 根据条件执行function，无入参，无返回值
     *
     * @param param     断言参数信息
     * @param predicate 断言方法
     * @param function  具体执行方法
     * @param <T>       断言参数类型
     */
    public static <T> void functionIfPre(T param, @NonNull Predicate<T> predicate, @NonNull Runnable function) {
        if (predicate.test(param)) {
            function.run();
        }
    }

    /**
     * 根据条件执行function，无入参，无返回值
     *
     * @param param        断言参数信息
     * @param predicate    断言方法
     * @param function     具体执行方法
     * @param elseFunction 断言不成立执行的方法
     * @param <T>          断言参数类型
     */
    public static <T> void functionIfPre(T param, @NonNull Predicate<T> predicate, @NonNull Runnable function, @NonNull Runnable elseFunction) {
        if (predicate.test(param)) {
            function.run();
        } else {
            elseFunction.run();
        }
    }

    /**
     * 根据条件执行function 有返回值
     *
     * @param predicate 断言方法
     * @param function  具体执行方法
     * @param param     参数信息,断言参数
     * @param <T>       入参类型
     * @param <R>       返回数据类型
     * @return 执行方法后返回数据
     */
    public static <T, R> R functionIfPre(T param, @NonNull Predicate<T> predicate, @NonNull Function<T, R> function, R result) {
        if (predicate.test(param)) {
            return function.apply(param);
        } else {
            return result;
        }
    }

    /**
     * 根据条件执行function 无返回值
     *
     * @param predicate 断言方法
     * @param function  具体执行方法
     * @param param     参数信息，断言参数
     * @param <T>       入参类型
     */
    public static <T> void functionIfPre(T param, @NonNull Predicate<T> predicate, @NonNull Consumer<T> function) {
        if (predicate.test(param)) {
            function.accept(param);
        }
    }

    /**
     * 根据条件执行function 无返回值
     *
     * @param predicate 断言方法
     * @param function  具体执行方法
     * @param param     参数信息，断言参数
     * @param <T>       入参类型
     */
    public static <T> void functionIfPre(T param, @NonNull Predicate<T> predicate, @NonNull Consumer<T> function, @NonNull Consumer<T> elseFunction) {
        if (predicate.test(param)) {
            function.accept(param);
        } else {
            elseFunction.accept(param);
        }
    }

    /**
     * 根据条件执行function 无返回值
     *
     * @param predicate 断言方法
     * @param function  具体执行方法
     * @param param     参数信息，断言参数
     * @param <T>       入参类型
     */
    public static <T, P> void functionIfPre(T param, @NonNull Predicate<T> predicate, @NonNull Consumer<T> function, @NonNull Consumer<P> elseFunction, P elseParam) {
        if (predicate.test(param)) {
            function.accept(param);
        } else {
            elseFunction.accept(elseParam);
        }
    }

    /**
     * 根据条件执行function 有返回值
     *
     * @param param      断言参数信息
     * @param predicate  断言方法
     * @param biFunction 具体执行方法
     * @param param1     参数信息1
     * @param param2     参数信息2
     * @param <T>        参数1类型
     * @param <U>        参数2类型
     * @param <R>        返回数据类型
     * @param <P>        断言参数类型
     * @return 执行方法后返回数据
     */
    public static <T, P, U, R> R functionIfPre(T param, @NonNull Predicate<T> predicate, @NonNull BiFunction<P, U, R> biFunction, P param1, U param2, R result) {
        if (predicate.test(param)) {
            return biFunction.apply(param1, param2);
        } else {
            return result;
        }
    }

    /**
     * 根据条件执行function 无返回值
     *
     * @param param      断言参数信息
     * @param predicate  断言方法
     * @param biFunction 具体执行方法
     * @param param1     参数信息1
     * @param param2     参数信息2
     * @param <T>        参数1类型
     * @param <U>        参数2类型
     * @param <P>        断言参数类型
     */
    public static <T, P, U> void functionIfPre(T param, @NonNull Predicate<T> predicate, @NonNull BiConsumer<P, U> biFunction, P param1, U param2) {
        if (predicate.test(param)) {
            biFunction.accept(param1, param2);
        }
    }

    /**
     * 根据条件执行function 有返回值
     *
     * @param bool     是否执行判断条件
     * @param function 具体执行方法
     * @param <R>      返回数据类型
     * @return 执行方法后返回数据
     */
    public static <R> R functionIf(@NonNull Boolean bool, @NonNull Supplier<R> function, R result) {
        if (bool) {
            return function.get();
        } else {
            return result;
        }
    }

    /**
     * 根据条件执行function，无入参，无返回值
     *
     * @param bool     是否执行判断条件
     * @param function 具体执行方法
     */
    public static void functionIf(@NonNull Boolean bool, @NonNull Runnable function) {
        if (bool) {
            function.run();
        }
    }

    /**
     * 根据条件执行function，无入参，无返回值
     *
     * @param bool         是否执行判断条件
     * @param function     具体执行方法
     * @param elseFunction 条件不成立执行的方法
     */
    public static void functionIf(@NonNull Boolean bool, @NonNull Runnable function, @NonNull Runnable elseFunction) {
        if (bool) {
            function.run();
        } else {
            elseFunction.run();
        }
    }

    /**
     * 根据条件执行function 有返回值
     *
     * @param bool     是否执行判断条件
     * @param function 具体执行方法
     * @param param    参数信息
     * @param <T>      入参类型
     * @param <R>      返回数据类型
     * @return 执行方法后返回数据
     */
    public static <T, R> R functionIf(@NonNull Boolean bool, @NonNull Function<T, R> function, T param, R result) {
        if (bool) {
            return function.apply(param);
        } else {
            return result;
        }
    }

    /**
     * 根据条件执行function 无返回值
     *
     * @param bool     是否执行判断条件
     * @param function 具体执行方法
     * @param param    参数信息
     * @param <T>      入参类型
     */
    public static <T> void functionIf(@NonNull Boolean bool, @NonNull Consumer<T> function, T param) {
        if (bool) {
            function.accept(param);
        }
    }

    /**
     * 根据条件执行function 无返回值
     *
     * @param bool     是否执行判断条件
     * @param function 具体执行方法
     * @param param    参数信息
     * @param <T>      入参类型
     */
    public static <T> void functionIf(@NonNull Boolean bool, @NonNull Consumer<T> function, T param, @NonNull Consumer<T> elseFunction) {
        if (bool) {
            function.accept(param);
        } else {
            elseFunction.accept(param);
        }
    }

    /**
     * 根据条件执行function 无返回值
     *
     * @param bool     是否执行判断条件
     * @param function 具体执行方法
     * @param param    参数信息
     * @param <T>      入参类型
     */
    public static <T, P> void functionIf(@NonNull Boolean bool, @NonNull Consumer<T> function, T param, @NonNull Consumer<P> elseFunction, P elseParam) {
        if (bool) {
            function.accept(param);
        } else {
            elseFunction.accept(elseParam);
        }
    }

    /**
     * 根据条件执行function 有返回值
     *
     * @param bool       是否执行判断条件
     * @param biFunction 具体执行方法
     * @param param1     参数信息1
     * @param param2     参数信息2
     * @param <T>        参数1类型
     * @param <P>        参数2类型
     * @param <R>        返回数据类型
     * @return 执行方法后返回数据
     */
    public static <T, P, R> R functionIf(@NonNull Boolean bool, @NonNull BiFunction<T, P, R> biFunction, T param1, P param2, R result) {
        if (bool) {
            return biFunction.apply(param1, param2);
        } else {
            return result;
        }
    }

    /**
     * 根据条件执行function 无返回值
     *
     * @param bool       是否执行判断条件
     * @param biFunction 具体执行方法
     * @param param1     参数信息1
     * @param param2     参数信息2
     * @param <T>        参数1类型
     * @param <P>        参数2类型
     */
    public static <T, P> void functionIf(@NonNull Boolean bool, @NonNull BiConsumer<T, P> biFunction, T param1, P param2) {
        if (bool) {
            biFunction.accept(param1, param2);
        }
    }

    /**
     * 根据条件执行function
     *
     * @param bool     执行条件
     * @param function 执行方法
     * @param result   默认结果
     * @param <R>      执行方法返回类型
     * @return 执行结果返回包装类
     */
    public static <R> AssertResult<R> functionIfThen(@NonNull Boolean bool, @NonNull Supplier<R> function, R result) {
        AssertResult<R> assertResult = new AssertResult<>();
        if (bool) {
            assertResult.setValue(function.get());
        } else {
            assertResult.setValue(result);
        }
        return assertResult;
    }

    /**
     * 根据条件执行function
     *
     * @param function 执行方法
     * @param result   默认结果
     * @param <R>      执行方法返回类型
     * @return 执行结果返回包装类
     */
    public static <T, R> AssertResult<R> functionIfThen(T param, @NonNull Predicate<T> predicate, @NonNull Supplier<R> function, R result) {
        AssertResult<R> assertResult = new AssertResult<>();
        if (predicate.test(param)) {
            assertResult.setValue(function.get());
        } else {
            assertResult.setValue(result);
        }
        return assertResult;
    }

    /**
     * 根据条件执行function
     *
     * @param bool     执行条件
     * @param param    执行参数
     * @param function 执行方法
     * @param <T>      执行方法入参类型
     * @param <R>      执行方法返回类型
     * @return 执行结果返回包装类
     */
    public static <T, R> AssertResult<R> functionIfThen(T param, @NonNull Boolean bool, @NonNull Function<T, R> function) {
        AssertResult<R> assertResult = new AssertResult<>();
        if (bool) {
            assertResult.setValue(function.apply(param));
        }
        return assertResult;
    }

    /**
     * 根据条件执行function
     *
     * @param bool     执行条件
     * @param param    执行参数
     * @param function 执行方法
     * @param result   默认结果
     * @param <T>      执行方法入参类型
     * @param <R>      执行方法返回类型
     * @return 执行结果返回包装类
     */
    public static <T, R> AssertResult<R> functionIfThen(T param, @NonNull Boolean bool, @NonNull Function<T, R> function, R result) {
        AssertResult<R> assertResult = new AssertResult<>();
        if (bool) {
            assertResult.setValue(function.apply(param));
        } else {
            assertResult.setValue(result);
        }
        return assertResult;
    }

    /**
     * 根据条件执行function
     *
     * @param predicate 断言
     * @param param     断言参数，入参
     * @param function  执行方法
     * @param result    默认结果
     * @param <T>       执行方法入参类型
     * @param <R>       执行方法返回类型
     * @return 执行结果返回包装类
     */
    public static <T, R> AssertResult<R> functionIfThen(T param, @NonNull Predicate<T> predicate, @NonNull Function<T, R> function, R result) {
        AssertResult<R> assertResult = new AssertResult<>();
        if (predicate.test(param)) {
            assertResult.setValue(function.apply(param));
        } else {
            assertResult.setValue(result);
        }
        return assertResult;
    }

    /**
     * 根据条件执行function
     *
     * @param predicate 断言
     * @param param     断言参数，入参
     * @param function  执行方法
     * @param <T>       执行方法入参类型
     * @param <R>       执行方法返回类型
     * @return 执行结果返回包装类
     */
    public static <T, R> AssertResult<R> functionIfThen(T param, @NonNull Predicate<T> predicate, @NonNull Function<T, R> function) {
        AssertResult<R> assertResult = new AssertResult<>();
        if (predicate.test(param)) {
            assertResult.setValue(function.apply(param));
        }
        return assertResult;
    }

    @Data
    public static class AssertResult<R> implements Serializable {

        private static final long serialVersionUID = 1L;

        /**
         * 执行结果
         */
        public R value;

        /**
         * 下一步执行逻辑,有默认返回值
         *
         * @param predicate 断言，判断上一次执行结果
         * @param function  执行的方法，入参为上一次执行完成后返回的结果信息
         * @param result    断言失败默认返回值，当断言为否时默认返回的数据
         * @param <P>       执行方法返回类型
         * @return 结果
         */
        public <P> AssertResult<P> thenRun(@NonNull Predicate<R> predicate, @NonNull Function<R, P> function, P result) {
            AssertResult<P> assertResult = new AssertResult<>();
            if (predicate.test(value)) {
                assertResult.setValue(function.apply(this.value));
            } else {
                assertResult.setValue(result);
            }
            return assertResult;
        }

        /**
         * 下一步执行逻辑, 无默认返回值
         *
         * @param predicate 断言，判断上一次执行结果
         * @param function  执行的方法，入参为上一次执行完成后返回的结果信息
         * @param <P>       执行方法返回类型
         * @return 结果
         */
        public <P> AssertResult<P> thenRun(@NonNull Predicate<R> predicate, @NonNull Function<R, P> function) {
            AssertResult<P> assertResult = new AssertResult<>();
            if (predicate.test(value)) {
                assertResult.setValue(function.apply(this.value));
            }
            return assertResult;
        }

        /**
         * 下一步执行逻辑, 无入参, 无默认返回值
         *
         * @param predicate 断言，判断上一次执行结果
         * @param function  执行方法，入参为上一次执行完成后返回的结果信息
         */
        public void thenRun(@NonNull Predicate<R> predicate, @NonNull Runnable function) {
            if (predicate.test(value)) {
                function.run();
            }
        }

        /**
         * 获取最终执行结果信息
         *
         * @return 执行结果
         */
        public R get() {
            return this.value;
        }

    }

}
